package org.moonlight.jvm.instructions.loads.xaload;

import org.moonlight.jvm.instructions.base.NoOperandsInstruction;
import org.moonlight.jvm.rtda.exclusive.Frame;
import org.moonlight.jvm.rtda.exclusive.OperandStack;
import org.moonlight.jvm.rtda.share.Object;

/**
 * x_a_load: 指令: 按索引取数组元素值，然后推入操作数栈
 *
 * @author Moonlight
 * @createTime 2023/9/15 14:27
 **/
public abstract class XALoad  extends NoOperandsInstruction {

    @Override
    public void execute(Frame frame) {
        // 操作数栈
        OperandStack stack = frame.getOperandStack();
        // 下标索引
        int idx = stack.popInt();
        // 数组引用
        Object arrRef = stack.popRef();

        checkNotNull(arrRef);

        xLoad(stack, idx, arrRef);
    }

    /**
     * 1. 将 数组引用 转为对应类型的 数组
     * 2. 根据 数组对应 索引下标 进行越界检查
     * 3. 将 数组中 索引下标 位置的 数据 压入操作数栈的栈顶
     *
     * @param stack 操作数栈
     * @param idx 索引下标
     * @param arrRef 数组引用
     * @createTime 14:36 2023/9/15
     * @author moonlight
     **/
    protected abstract void xLoad(OperandStack stack, int idx, Object arrRef);

    protected void checkNotNull(Object ref) {
        if (ref == null) {
            throw new NullPointerException();
        }
    }

    protected void checkIndex(int arrLen, int idx) {
        if (idx < 0 || idx >= arrLen) {
            throw new ArrayIndexOutOfBoundsException();
        }
    }

}
